Ranges and Views in C++20
The following article is from CPP编程客 Author 里缪
什么是Ranges和Views?
概念 | 解释 |
---|---|
range | 可迭代区间的抽象概念 |
range algo | 可接受Ranges的算法 |
view | 轻便、惰性的Ranges |
range adaptor | 创建Views的适配器 |
一个begin迭代器,和一个end迭代器
一个begin迭代器,和一个结束标识符(sentinel)
一个begin迭代器,和元素数量
数组元素
template <auto T>
struct end_with {
bool operator==(auto pos) const {
return *pos == T;
}
};
int main() {
std::vector vec { 7, 2, 15, 20, 9 };
// 1. Ranges of begin and end iterator
auto rng = std::ranges::subrange(vec);
fmt::print("Ranges of begin and end iterator: {}\n", rng);
// 2. Ranges of begin and a sentinel
std::ranges::subrange rng_sentinel {vec.begin(), end_with<20>{}};
fmt::print("Ranges of begin and a sentinel: {}\n", rng_sentinel);
// 3. Ranges of begin and a count
auto pos = std::ranges::find(vec, 2);
if (std::ranges::distance(pos, vec.end()) >= 3) {
auto rng_count = std::views::counted(pos, 3);
fmt::print("Ranges of begin and a count: {}\n", rng_count);
}
// 4. Ranges of an array
int arr[] = { 7, 2, 15, 20, 9 };
auto rng_arr = std::ranges::subrange(arr);
fmt::print("Ranges of an array: {}", rng_arr);
}
Ranges of begin and end iterator: [7, 2, 15, 20, 9]
Ranges of begin and a sentinel: [7, 2, 15]
Ranges of begin and a count: [2, 15, 20]
Ranges of an array: [7, 2, 15, 20, 9]
std::vector v1 { 7, 2, 15, 20, 9 };
auto v2(v1);
// sort with STL
std::sort(v1.begin(), v1.end());
fmt::print("sort with STL: {}\n", v1);
// sort with ranges
std::ranges::sort(v2);
fmt::print("sort with ranges: {}", v2);
//////////
// Output:
sort with STL: [2, 7, 9, 15, 20]
sort with ranges: [2, 7, 9, 15, 20]
std::ranges::take_view
std::ranges::filter_view
std::ranges::transform_view
std::ranges::drop_view
std::ranges::join_view
std::ranges::split_view
std::ranges::keys_view
std::ranges::values_view
std::ranges::iota_view
std::views::take
std::views::filter
std::views::transform
std::views::drop
std::views::join
std::views::split
std::views::keys
std::views::values
Ranges算法
std::vector vec { 1, 2, -1, -2};
auto is_positive = [](int n) { return n > 0; };
auto res_all_of = std::ranges::all_of(vec, is_positive);
auto res_any_of = std::ranges::any_of(vec, is_positive);
fmt::print("vec中的所有元素皆大于0: {}\n", res_all_of);
fmt::print("vec中存在元素大于0:{}\n", res_any_of);
/////////
// Output:
vec中的所有元素皆大于0: false
vec中存在元素大于0:true
std::vector vec { "monster", "monadic", "buggy", "cooper", "resurrent", "mono"};
// std::ranges::count_if
auto res_count_if = std::ranges::count_if(vec, [](const std::string& item) {
return item.starts_with("mon");
});
fmt::print("以mon开头的元素个数为: {}\n", res_count_if);
// std::ranges::find_if
const auto& res_find_if = std::ranges::find_if(vec, [](const std::string& item) {
return item.ends_with("er");
});
if(res_find_if != std::end(vec)) {
fmt::print("首个以er结尾的元素:{}\n", *res_find_if);
}
//////////
// Output:
以mon开头的元素个数为: 3
首个以er结尾的元素:monster
std::string s1 { "ABBCD" };
std::string s2 { "ABBEF" };
auto [n1, n2] = std::ranges::mismatch(s1, s2);
const auto pos = std::distance(std::begin(s1), n1);
fmt::print("s1和s2不匹配位置:{}", pos);
//////////
// Output:
s1和s2不匹配位置:3
std::vector v1 { 1, 5, 2, 3, 4, 7, 8 };
std::vector v2 { 2, 3, 4 };
auto res = std::ranges::search(v1, v2);
if(!res.empty()) {
const auto pos1 = std::distance(v1.begin(), res.begin());
const auto pos2 = std::distance(v1.begin(), res.end());
fmt::print("搜索的结果位于{}-{}\n", pos1, pos2);
}
//////////
// Output:
搜索的结果位于2-5
std::vector<int> v(10);
std::iota(v.begin(), v.end(), 1);
fmt::print("v: {}\n", v);
std::random_device rd;
std::mt19937 gen{rd()};
std::ranges::shuffle(v, gen);
fmt::print("shuffle v: {}\n", v);
//////////
// Output:
v: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
shuffle v: [4, 7, 8, 1, 6, 10, 2, 3, 9, 5]
Views
int main() {
std::vector<int> v;
auto is_odd = [](int i) { return i % 2 == 1; };
for (int i : std::views::iota(1)
| std::views::take(20)
| std::views::filter(is_odd)) {
v.push_back(i);
}
fmt::print("The answer is: {}", v);
}
// Output:
The answer is: [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
// pipe symbol
A() | B() | C()
// nested syntax
C(B(A()))
std::vector<int> v;
auto filter = [](int i) {
fmt::print("FILTER\n");
return i % 2 == 0;
};
auto transform = [](int i) {
fmt::print("TRANSFORM\n");
return i * i;
};
auto lazy_range = std::views::iota(1, 10)
| std::views::filter(filter)
| std::views::transform(transform);
fmt::print("---lazy range print---\n");
for (auto i : lazy_range) {
fmt::print("The element is {}\n", i);
}
---lazy range print---
FILTER
FILTER
TRANSFORM
The element is 4
FILTER
FILTER
TRANSFORM
The element is 16
FILTER
FILTER
TRANSFORM
The element is 36
FILTER
FILTER
TRANSFORM
The element is 64
FILTER
auto is_even = [](int i) { return i % 2 == 0; };
const auto view = std::views::iota(1, 10)
| std::views::filter(is_even);
// ERROR
auto begin = std::ranges::begin(view);
auto end = std::ranges::end(view);
std::ranges::filter_view
std::range::drop_while_view
std::ranges::split_view
std::ranges::drop_view
std::ranges::reverse_view
std::ranges::join_view
C++20 Ranges的缺点与局限
总结
- EOF -
加主页君微信,不仅C/C++技能+1
主页君日常还会在个人微信分享C/C++开发学习资源和技术文章精选,不定期分享一些有意思的活动、岗位内推以及如何用技术做业余项目
加个微信,打开一扇窗
关注『CPP开发者』
看精选C/C++技术文章
点赞和在看就是最大的支持❤️